using System;
using UnityEngine;

[Serializable]
public struct CameraParameter
{
    public bool limitXAngle;
    public float minXAngle;
    public float maxXAngle;

    public bool limitYAngle;
    public float minYAngle;
    public float maxYAngle;

    public float orbitSensitive;
    public float mouseMoveRatio;

    public CameraParameter(bool limitXAngle=true
        ,float minXAngle=0f
        ,float maxXAngle=80f
        ,bool limitYAngle=false
        ,float minYAngle=0f
        ,float maxYAngle=0f
        ,float orbitSensitive=10f
        ,float mouseMoveRatio=0.3f)
    {
        this.limitXAngle = limitXAngle;
        this.minXAngle = minXAngle;
        this.maxXAngle = maxXAngle;
        this.limitYAngle = limitYAngle;
        this.minYAngle = minYAngle;
        this.maxYAngle = maxYAngle;
        this.orbitSensitive = orbitSensitive;
        this.mouseMoveRatio = mouseMoveRatio;
    }

}

public class CameraOrbit : MonoBehaviour
{
    public Transform m_cameraRootTF;
    public Transform m_cameraTF;
    
    public CameraParameter m_currentOrbitParameter;
    public float m_minDistance = 5f;
    public float m_maxDistance = 30f;
    public float m_mouseScrollRatio = 1f;
    public float m_zoomSensitive = 1f;

    public float[] m_yMinAngles;
    public float[] m_yMaxAngles;
    public bool[] m_isAlreadyFire;

    private Vector3 _lastMousePos;
    private Vector3 _targetEulerAngle;
    private Vector3 _eulerAngle;
    private Quaternion _originalRotate;
    private float _cameraDistance;
    private float _targetCameraDistance;
    private float _lastTouchDistance;

    private void Start()
    {
        _originalRotate = m_cameraRootTF.rotation;
        _cameraDistance = m_cameraTF.localPosition.z;
        _targetCameraDistance = _cameraDistance;
        m_isAlreadyFire = new bool[m_yMinAngles.Length];
    }

    private void Update()
    {
        if (GameManager.m_Instance.m_ChooseState != EChooseState.None) return;
        Orbit();
        Zoom();
    }

    private void Orbit()
    {
        if (Input.GetMouseButtonDown(0))
        {
            _lastMousePos = Input.mousePosition;
        }

        if (Input.GetMouseButton(0))
        {
            _targetEulerAngle.x += (-Input.mousePosition.y + _lastMousePos.y) * m_currentOrbitParameter.mouseMoveRatio;
            _targetEulerAngle.y += (-Input.mousePosition.x + _lastMousePos.x) * m_currentOrbitParameter.mouseMoveRatio;
            if (m_currentOrbitParameter.limitXAngle)
            {
                _targetEulerAngle.x = Mathf.Clamp(_targetEulerAngle.x, m_currentOrbitParameter.minXAngle,
                    m_currentOrbitParameter.maxXAngle);
            }

            if (m_currentOrbitParameter.limitYAngle)
            {
                _targetEulerAngle.y = Mathf.Clamp(_targetEulerAngle.y, m_currentOrbitParameter.minYAngle,
                    m_currentOrbitParameter.maxYAngle);
            }
            
            _lastMousePos = Input.mousePosition;
        }

        if (Input.touchCount < 2)
        {
            _eulerAngle = Vector3.Lerp(_eulerAngle, _targetEulerAngle,
                Time.fixedDeltaTime * m_currentOrbitParameter.orbitSensitive);
            m_cameraRootTF.rotation = _originalRotate * Quaternion.Euler(_eulerAngle);
        }

        FireEvent(m_cameraRootTF.localEulerAngles.y);
        
    }

    private void Zoom()
    {
        if (Input.touchCount < 2)
        {
            var scrollValue = Input.GetAxis("Mouse ScrollWheel");
            if (scrollValue != 0)
            {
                _cameraDistance = -m_cameraTF.localPosition.z;
                _targetCameraDistance =
                    _cameraDistance - scrollValue * _cameraDistance * m_mouseScrollRatio;
                _targetCameraDistance = Mathf.Clamp(_targetCameraDistance, m_minDistance, m_maxDistance);
            }
        }
        else
        {
            if (Input.GetTouch(1).phase==TouchPhase.Began)
            {
                _lastTouchDistance = Vector2.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position);
            }
            if (Input.GetTouch(1).phase==TouchPhase.Moved||Input.GetTouch(0).phase==TouchPhase.Moved)
            {
                _cameraDistance = -m_cameraTF.localPosition.z;
                _targetCameraDistance = _cameraDistance -
                                        (Vector2.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position) -
                                         _lastTouchDistance) * m_mouseScrollRatio;
                _lastMousePos = Input.mousePosition;
            }
        }

        if (Mathf.Abs(_targetCameraDistance - _cameraDistance) > 0.1f)
        {
            _cameraDistance = Mathf.Lerp(_cameraDistance, _targetCameraDistance, Time.fixedDeltaTime * m_zoomSensitive);
            m_cameraTF.localPosition = new Vector3(0f, 0f, -_cameraDistance);
        }
    }

    private void FireEvent(float yAngle)
    {
        for (int i = 0; i < m_yMinAngles.Length; i++)
        {
            if (yAngle > m_yMinAngles[i] && yAngle < m_yMaxAngles[i])
            {
                if (!m_isAlreadyFire[i])
                {
                    EventCenter.CameraEvent.RaiseMeshAnimEvent(i, true);
                    m_isAlreadyFire[i] = true;
                }
            }
            else
            {
                if (m_isAlreadyFire[i])
                {
                    EventCenter.CameraEvent.RaiseMeshAnimEvent(i, false);
                    m_isAlreadyFire[i] = false;
                }
            }
        }
    }
}
